#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>
#include "oled.h"
#include "oledfont.h"

#define channel 0
#define vccstate OLED_SWITCHCAPVCC
#define width 128
#define height 64
#define pages 8

#define RST 22
#define DC  21
unsigned char buffer[1024];

void command(unsigned char cmd)
{
    digitalWrite(DC,LOW);
    wiringPiSPIDataRW(channel,&cmd,1);
}

void OLED_init()
{
	pinMode(RST,OUTPUT);
	pinMode(DC,OUTPUT);
	wiringPiSPISetup(channel,2000000);    //2M
	
	digitalWrite(RST,HIGH);
	delay(10);
	digitalWrite(RST,LOW);
	delay(10);
	digitalWrite(RST,HIGH);

    command(OLED_DISPLAYOFF);
    command(OLED_SETDISPLAYCLOCKDIV);
    command(0x80);                              // the suggested ratio 0x80

    command(OLED_SETMULTIPLEX);
    command(0x3F);
    command(OLED_SETDISPLAYOFFSET);
    command(0x0);                               // no offset
    command(OLED_SETSTARTLINE | 0x0);        // line #0
    command(OLED_CHARGEPUMP);
    command((vccstate == OLED_EXTERNALVCC) ? 0x10 : 0x14);

    command(OLED_MEMORYMODE);
    command(0x00);                              // 0x0 act like ks0108

    command(OLED_SEGREMAP | 0x1);
    command(OLED_COMSCANDEC);
    command(OLED_SETCOMPINS);
    command(0x12);           // TODO - calculate based on _rawHieght ?
    command(OLED_SETCONTRAST);
    command((vccstate == OLED_EXTERNALVCC) ? 0x9F : 0xCF);
    command(OLED_SETPRECHARGE);
    command((vccstate == OLED_EXTERNALVCC) ? 0x22 : 0xF1);
    command(OLED_SETVCOMDETECT);
    command(0x40);
    command(OLED_DISPLAYALLON_RESUME);
    command(OLED_NORMALDISPLAY);
    command(OLED_DISPLAYON);
}
void OLED_clear()
{
	int i;
	for(i = 0;i<sizeof(buffer);i++)
	{
		buffer[i] = 0;
	}
}
void OLED_pixel(int x,int y,char color)
{
    if(x > width || y > height)return ;
    if(color)
	{
        buffer[x+(y/8)*width] |= 1<<(y%8);
	}else
	{
        buffer[x+(y/8)*width] &= ~(1<<(y%8));
	}
}
void OLED_char1616(unsigned char x,unsigned char y,unsigned char chChar)
{
	unsigned char i, j;
	unsigned char chTemp = 0, y0 = y, chMode = 0;

	for (i = 0; i < 32; i ++) {
		chTemp = Font1612[chChar - 0x30][i];
		for (j = 0; j < 8; j ++) {
			chMode = chTemp & 0x80? 1 : 0; 
            OLED_pixel(x, y, chMode);
			chTemp <<= 1;
			y ++;
			if ((y - y0) == 16) {
				y = y0;
				x ++;
				break;
			}
		}
	}
}

void OLED_char3216(unsigned char x,unsigned char y,unsigned char chChar)
{
	unsigned char i, j;
	unsigned char chTemp = 0, y0 = y, chMode = 0;

	for (i = 0; i < 64; i ++) {
		chTemp = Font3216[chChar - 0x30][i];
		for (j = 0; j < 8; j ++) {
			chMode = chTemp & 0x80? 1 : 0; 
            OLED_pixel(x, y, chMode);
			chTemp <<= 1;
			y ++;
			if ((y - y0) == 32) {
				y = y0;
				x ++;
				break;
			}
		}
	}
}
void OLED_char(unsigned char x,unsigned char y,char acsii,char size,char mode)
{
	unsigned char i,j,y0=y;
	char temp;
	unsigned char ch = acsii - ' ';
	for(i = 0;i<size;i++)
	{
		if(size == 12)
		{
			if(mode)temp=Font1206[ch][i];
			else temp = ~Font1206[ch][i];
		}
		else 
		{			
			if(mode)temp=Font1608[ch][i];
			else temp = ~Font1608[ch][i];
		}
		for(j =0;j<8;j++)
		{
            if(temp & 0x80) OLED_pixel(x,y,1);
            else OLED_pixel(x,y,0);
			temp <<=1;
			y++;
			if((y-y0)==size)
			{
				y = y0;
				x ++;
				break;
			}
		}
	}
}
void OLED_string(unsigned char x,unsigned char y, const char *pString,
					unsigned char Size,unsigned char Mode)
{
    while (*pString != '\0') {       
        if (x > (width - Size / 2)) {
			x = 0;
			y += Size;
			if (y > (height - Size)) {
				y = x = 0;
			}
		}
		
        OLED_char(x, y, *pString, Size, Mode);
        x += Size / 2;
        pString ++;
    }
}

void OLED_bitmap(unsigned char x,unsigned char y,const unsigned char *pBmp,
					char chWidth,char chHeight)
{
	unsigned char i,j,byteWidth = (chWidth + 7)/8;
	for(j = 0;j < chHeight;j++)
	{
		for(i = 0;i < chWidth;i++)
		{
			if(*(pBmp +j*byteWidth+i/8) & (128 >> (i & 7)))
			{
                OLED_pixel(x+i,y+j,1);
			}
		}
	}		
}

void OLED_display()
{
    command(OLED_COLUMNADDR);
	command(0);         //cloumn start address
	command(width -1); //cloumn end address
    command(OLED_PAGEADDR);
	command(0);         //page atart address
	command(pages -1); //page end address
	digitalWrite(DC,HIGH);
	wiringPiSPIDataRW(channel,buffer,sizeof(buffer));
}

void OLED_ShowCHinese(unsigned char x, unsigned char y, unsigned char num, unsigned char size,unsigned char mode)
{
    unsigned char temp,t,t1;
    unsigned char y0=y;
    //u8 size = 16;
    unsigned char csize=(size/8 + ((size%8)?1:0)) * size;     //得到一个字体一个字符对应点阵集所占的字节数

    for(t=0;t<csize;t++)
    {
//         if(size==12)      temp = gbk_1212[num][t];    //调用1212字体
        if(size==16) temp = OLED_1616FC[num][t];  //调用1616字体
//      else if(size==24)temp=asc2_2412[chr][t];   //调用2412字体
        else return;                                //没有的字体库
              for(t1=0;t1<8;t1++)
        {
            if(temp&0x80)OLED_pixel(x,y,mode);
            else OLED_pixel(x,y,!mode);
            temp<<=1;
            y++;
            if((y-y0)==size)
            {
                y=y0;
                x++;
                break;
            }
        }
    }
}


